<?php

namespace Hiders\WebmanCrud\Base;

use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use support\Cache;
use support\Container;

class Model extends \support\Model
{
    /**
     * @var int getValue默认缓存秒数
     */
    protected static int $cacheTimeValue = 5;

    protected static array $tableName = [];

    /**
     * 创建模型实例
     * @param array $attributes 属性数组
     * @param bool  $save       是否直接保存
     * @return \Hiders\WebmanCrud\Base\Model
     */
    public static function new(array $attributes = [], bool $save = false): Model
    {
        $calledClass = get_called_class();

        $model = new $calledClass();

        if (!empty($attributes)) {
            $model->forceFill($attributes);
        }

        if ($save) {
            $model->save();
        }

        return $model;
    }

    /**
     * 获取单个字段的值
     * @param array|int|null $where   查询条件|主键
     * @param string         $field   字段名
     * @param bool           $refresh 是否强制刷新缓存
     * @return string|array|null
     */
    public static function getValue(array|int|null $where, string $field, bool $refresh = false): string|array|null
    {
        if (is_null($where)) {
            return null;
        }

        /** @var static $calledClass 调用类 */
        $calledClass = get_called_class();

        if (is_numeric($where)) {
            // $where = [[Single::new($calledClass)->getKeyName(), $where]];
            $where = [['id', $where]];
        } else {
            $where = (isset($where[0]) && is_string($where[0])) ? [$where] : $where;
        }

        $cacheKey = md5($calledClass . serialize($where) . $field);
        $res = Cache::get($cacheKey);
        if ($refresh || empty($res)) {
            $res = self::where($where)->value($field);
            Cache::set($cacheKey, $res ?? 'null', $calledClass::$cacheTimeValue);
        }

        return $res === 'null' ? null : $res;
    }

    /**
     * 获取单条记录
     * @param int|array|null $where
     * @param array          $columns
     * @return Collection|\Illuminate\Database\Eloquent\Model|null
     */
    public static function getInfo(int|array|null $where, array $columns = ['*']): \Illuminate\Database\Eloquent\Model|array|null
    {
        if (is_null($where)) {
            return null;
        }

        /** @var static $calledClass 调用类 */
        $calledClass = get_called_class();

        if ($columns[0] != '*') {
            array_unshift($columns, Container::get($calledClass)->getKeyName());
            $columns = array_unique($columns);
        }

        if (is_numeric($where)) {
            return $calledClass::find($where, $columns);
        } else {
            $where = (isset($where[0]) && is_string($where[0])) ? [$where] : $where;

            return self::where($where)->first($columns);
        }
    }

    /**
     * @param string $alias
     * @return Builder|\Illuminate\Database\Query\Builder
     */
    public static function alias(string $alias): Builder|\Illuminate\Database\Query\Builder
    {
        return self::from(self::table(), $alias);
    }

    /**
     * 获取表名
     * @param string|null $alias 别名
     * @return string
     */
    public static function table(?string $alias = null): string
    {
        $calledClass = get_called_class();
        if (!isset(self::$tableName[$calledClass])) {
            self::$tableName[$calledClass] = (new $calledClass)->getTable();
        }

        return self::$tableName[$calledClass] . (is_null($alias) || self::$tableName[$calledClass] === $alias ? '' : ' AS ' . $alias);
    }

    /**
     * 获取字段全名（表名.字段名）
     * @param string $field 字段名
     * @return string 表名.字段名
     */
    public static function field(string $field, ?string $alias = null): string
    {
        return self::table() . '.' . $field . (is_null($alias) ? '' : ' AS ' . $alias);
    }

    /**
     * 格式化时间
     * @param DateTimeInterface $date
     * @return string
     */
    protected function serializeDate(DateTimeInterface $date): string
    {
        return $date->format('Y-m-d H:i:s');
    }
}